import * as THREE from "three";
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
// import { TGALoader } from "three/examples/jsm/loaders/TGALoader";
import jsonData from "./aali.json";
// import { runOnce } from "./api";
// console.log(jsonData);
let camera, scene, renderer, stats;
import { aiGenerate } from "./getSteam";
const clock = new THREE.Clock();

var mixer;

init();
const audio = document.createElement("audio");
audio.id = "test";
document.body.appendChild(audio);
// aiGenerate({
//   text: "豫章故郡，洪都新府。星分翼轸，地接衡庐。襟三江而带五湖，控蛮荆而引瓯越。",
//   onmessage: (res) => {
//     if (res.startsWith("http")) {
//       return;
//     }
//     if (res.indexOf("phoneme") < 0) {
//       voice_list.push(res);
//       return;
//     }
//     const new_res = JSON.parse(res);
//     new_res.map((item, index) => {
//       if (index <= currentIndex) {
//         return;
//       }
//       action_list.push(item);
//     });
//     currentIndex = new_res.length - 1;

//     if (!play) {
//       playAudio();
//       play = true;
//     }
//     playAnimate();
//   }
// });
const BSNameMap = {
  a: "MouthFrownRight",
  i: "MouthClose",
  u: "MouthStretchRight",
  e: "MouthPressLeft",
  o: "NoseSneerLeft"
};
const BSIndexMap = {
  a: 19,
  e: 13,
  i: 14,
  o: 15,
  u: 16,
  ao: 0
};
const pinyinMap = {
  a: 19,
  e: 13,
  i: 14,
  o: 15,
  u: 16,
  ü: 16,
  ai: 19,
  ei: 13,
  ui: 14,
  ao: 17,
  ou: 15,
  iu: 16,
  ie: 13,
  üe: 16,
  er: 13,
  an: 19,
  en: 13,
  in: 14,
  un: 16,
  ün: 16,
  ang: 19,
  eng: 13,
  ing: 14,
  ong: 15
};
let current_audio = 0;
/*function playAudio() {
  // console.log("item", item);
  // console.log("进来", current_audio, voice_list.length);
  if (current_audio === voice_list.length) {
    return;
  }
  try {
    // 将字符串转换为UTF-8编码的字节
    // var utf8Bytes = new TextEncoder().encode(item);

    // 创建一个Blob对象，内容为这些字节
    // var blob = new Blob([item], {
    //   type: "audio/x-mpeg",
    // });
    // blob = window.URL.createObjectURL(blob);
    // console.log("125215215");
    // console.log(blob);
    audio.src = "data:audio/wav;base64," + voice_list[current_audio];
    // audio.onload = function () {
    //   console.log("load加载好");
    //   console.log(audio);
    // };
    audio.onplay = function () {
      console.log("开始播放");
      // playAnimate();
    };
    audio.onended = function () {
      current_audio++;
      // console.log("current_audio", current_audio);
      // console.log(voice_list.length);
      playAudio();
    };
    audio.onerror = function (err) {
      current_audio++;
      // console.log(err);
      playAudio();
    };
    audio.play();
    audio.addEventListener("timeupdate", function () {
      // console.log(audio.currentTime);
      if (audio.currentTime > 0 && current_audio === 0) {
        playBS();
      }
    });
  } catch (err) {
    console.log("12512521521");
    console.log(err);
  }
}*/
function init() {
  const container = document.createElement("div");
  document.body.appendChild(container);

  camera = new THREE.PerspectiveCamera(
    45,
    window.innerWidth / window.innerHeight,
    1,
    2000
  );
  camera.position.set(100, 200, 300);
  camera.lookAt(0, 0, 0);

  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xa0a0a0);
  //   scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000);

  const ambientLight = new THREE.AmbientLight(0xffffff);
  scene.add(ambientLight);

  // 创建点光 参数1 光的颜色，参数2 光的强度
  const pointLight = new THREE.PointLight(0xffffff, 1);
  // 点光源的位置
  pointLight.position.set(400, 300, 200);
  scene.add(pointLight);
  const hemiLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 1);
  hemiLight.position.set(0, 200, 0);
  scene.add(hemiLight);

  const dirLight = new THREE.DirectionalLight(0xffffff, 1);
  dirLight.position.set(1, 1, 1);
  scene.add(dirLight);
  // 聚光灯
  const spotLight = new THREE.SpotLight(0xffffff);
  spotLight.position.set(0, 200, 100);
  scene.add(spotLight);

  // scene.add( new THREE.CameraHelper( dirLight.shadow.camera ) );

  // ground
  const mesh = new THREE.Mesh(
    new THREE.PlaneGeometry(2000, 2000),
    new THREE.MeshBasicMaterial({ color: 0x999999, depthWrite: false })
  );
  mesh.rotation.x = -Math.PI / 2;
  mesh.receiveShadow = true;
  scene.add(mesh);
  //   const grid = new THREE.GridHelper(2000, 20, 0x000000, 0x000000);
  //   grid.material.opacity = 0.2;
  //   grid.material.transparent = true;
  //   scene.add(grid);
  //   // 平行光
  //   const directionalLight = new THREE.DirectionalLight(0xffffff, 0.4);
  //   // 设置光源的方向：通过光源position属性和目标指向对象的position属性计算
  //   directionalLight.position.set(80, 100, 50);
  //   // 方向光指向对象网格模型mesh，可以不设置，默认的位置是0,0,0
  //   directionalLight.target = mesh;
  //   scene.add(directionalLight);
  // model
  const loader = new FBXLoader();
  loader.load("static/Face3.fbx", function (object) {
    // mixer = new THREE.AnimationMixer(object);

    // const action = mixer.clipAction(object.animations[0]);
    // action.play();
    console.log("obj", object);
    object.scale.set(1.1, 1.1, 1.1);
    object.position.set(1, 1, 0);
    object.traverse(function (child) {
      console.log("child", child);
      if (child.isMesh) {
        console.log("child2", child);
        child.clearColor = 0x00ff00;
        // var loader = new TGALoader();
        // const material = new THREE.MeshBasicMaterial({
        //   color: 0xffffff
        // });
        // child.material = material;
        var texture = new THREE.TextureLoader();
        const res = texture.load("static/Face.png");
        res.encoding = THREE.sRGBEncoding; // 设置纹理的颜色空间（普通的纹理）
        const material = new THREE.MeshBasicMaterial({ map: res });
        child.material = material;

        if (child.name === "Face") {
          mixer = new THREE.AnimationMixer(child); //创建混合器
        }
        // child.morphTargetInfluences[0] = 1;
        // child.morphTargetInfluences[1] = 1;
        // child.material.map = texture;
        // 设置材质的自发光颜色和强度
        // child.material.emissive = new THREE.Color(0x000000); // 黑色
        child.castShadow = true;
        child.receiveShadow = true;
      }
    });

    scene.add(object);
  });

  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.shadowMap.enabled = true;
  container.appendChild(renderer.domElement);

  const controls = new OrbitControls(camera, renderer.domElement);
  controls.target.set(0, 100, 0);
  controls.update();

  window.addEventListener("resize", onWindowResize);

  //   // stats
  //   stats = new Stats();
  //   container.appendChild(stats.dom);
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

//

let lastActionIndex = 0;

let infoList = {};
function playAnimate() {
  // console.log("actionIndex", lastActionIndex);
  action_list.map((item, index) => {
    if (lastActionIndex > 0 && lastActionIndex >= index) {
      return;
    }
    try {
      // 解析并存储
      // console.log("item", item);
      const clip = getAnimationClip(item);
      infoList.clip = clip;
      console.log("clip", infoList.clip);
    } catch (err) {
      console.log("xxxx");
      console.log(err);
    }
  });
  lastActionIndex = action_list.length - 1;
  console.log("infoList", infoList.clip);
}
let last_end_time = 0;
let timeAxis = [0]; // 时间轴，取结尾时间
let morphs = {}; // 每个BS按时间轴顺序变化的权重值
// 因为模型的BS数量以及命名不一定与接口数据完全重合，所以我们自己做了一个映射关系
// BSNameMap 模型中BS名称与接口BS名称对应关系
// BSIndexMap 模型中BS名称在变形动画权重数组中的下标对应关系
Object.keys(BSIndexMap).forEach((key) => {
  morphs[key] = [0]; // 初始化morphs
});

/** 获取动画数据 这里是解析某一句话的BS动画*/
const getAnimationClip = (ele) => {
  let tracks = []; // 关键帧动画数据集
  // console.log("ele", ele);

  // console.log("morphs", bsList);
  // bsList.forEach((ele, index) => {
  const { end_time } = ele;
  // console.log("time_oout", end_time / 1000, last_end_time);
  timeAxis.push(end_time / 1000); // push到时间轴中
  // 按时间节点给BS权重赋值
  // console.log("ele", ele);
  Object.keys(morphs).forEach((key) => {
    let item = ele.phoneme_list.find((res) => res.phoneme.indexOf(key) > -1);
    // 如果能从接口数据中取到BS权重，则push给当前BS
    //   if (BSNameMap[key]) {
    //     console.log("key", key);
    //     console.log("BSNameMap", BSNameMap[key]);
    //     console.log("ele", ele[BSNameMap[key]]);
    //   }
    if (item) {
      // console.log("tone", parseInt(item.tone) / 10, key);
      morphs[key].push(parseInt(item.tone) / 10 + Math.random());
    } else {
      // 如果取不到则沿用上一个时间节点的数据或者设置为默认权重0
      morphs[key].push(0);
    }
  });
  // });
  // console.log("morphs", morphs);

  // 根据morphs来生成每个BS按时间轴变化的关键帧动画
  Object.keys(morphs).forEach((key) => {
    // 控制BS权重值按时间轴timeAxis进行变化
    const track = new THREE.KeyframeTrack(
      `.morphTargetInfluences[${BSIndexMap[key]}]`,
      timeAxis,
      morphs[key]
    );
    tracks.push(track);
  });
  // console.log("tracks", tracks);
  // 创建一个剪辑clip对象，命名"default"
  // 这个剪辑对象可以用来播放，播放后的动作就是当前解析的这句话的面部表情动作
  const time = tracks[tracks.length - 1].times;
  const clip = new THREE.AnimationClip(
    "default",
    time[time.length - 1],
    tracks
  );
  // last_end_time = time[time.length - 1];
  // console.log("last_end_time", last_end_time);
  // console.log("last_time", time[time.length - 1] - last_end_time);
  console.log("tracks", tracks);

  return clip;
};
// }
/** 播放bs */
let playIndex = 0; // 当前播放的下标
let AnimationAction;
const playBS = () => {
  // console.log("xxxxxxx", infoList.value);
  // console.log("playBS", infoList, playIndex, infoList.value.length);
  // 判断是否全部都播放完毕
  // if (playIndex < infoList.value.length) {
  console.log("mixer", infoList.clip);
  // playIndex = infoList[0].clip.duration;
  // infoList.value[playIndex].audio.play(); // 播放音频
  AnimationAction = mixer.clipAction(infoList.clip); //返回动画操作对象
  AnimationAction.timeScale = 1;
  // console.log("xxxxx", AnimationAction);
  // console.log("clip", infoList.value[playIndex].clip);
  AnimationAction.loop = THREE.LoopOnce; //不循环播放
  // console.log("play");
  AnimationAction.play();
  // AnimationAction.reset();
  // playIndex++; // 播放完成之后继续播放下一个
  // infoList.value.shift(); // 移除已经播放完毕的元素
  // playBS();
  // setTimeout(() => {
  //   playBS();
  // }, playIndex);
};
// setTimeout(() => {
//   playBS();
// }, 1000);

function animate() {
  requestAnimationFrame(animate);

  if (mixer) mixer.update(clock.getDelta());

  renderer.render(scene, camera);
  //   renderer.outputEncoding = THREE.sRGBEncoding;
  //   stats.update();
}
animate();

let isDone = false; // 是否传输结束
let isReady = true; // 是否准备好下一次加载
let bufferList = []; // 缓冲区数组
let steamStr = "";
let currentIndex = 0;

let voice_list = [];
let action_list = [];
let play = false;

const mediaSource = new MediaSource();
let sourceBuffer;
const url = window.URL.createObjectURL(mediaSource);
// 检测是否为open状态，否则添加监听器，等到open状态就绪后再传输
if (mediaSource.readyState === "open") {
  createSourceBuffer();
} else {
  mediaSource.addEventListener("sourceopen", () => {
    sourceBuffer = mediaSource.addSourceBuffer("audio/mpeg");
    createSourceBuffer();
  });
}
audio.src = url;

// 发送请求并开始传输
const createSourceBuffer = () => {
  // 传输完毕事件监听器
  sourceBuffer.addEventListener("updateend", () => {
    if (bufferList.length !== 0) {
      // 读取完毕后缓冲区有数据，从缓冲区读取
      sourceBuffer.appendBuffer(bufferList.shift());
    } else {
      // 缓冲区无数据
      if (isDone) {
        // 传输结束，关闭
        sourceBuffer.abort();
        mediaSource.endOfStream();
      } else {
        isReady = true; // 准备好进行下一次传输
      }
    }
    // console.log("media", mediaSource);
  });
  const text =
    "豫章故郡，洪都新府。星分翼轸，地接衡庐。襟三江而带五湖，控蛮荆而引瓯越";
  window
    .fetch("http://audio.lolikon.cc/stream?text=" + text, {
      method: "get",
      data: JSON.stringify({
        stream: true
      }),
      headers: {
        "Content-Type": "text/event-stream"
      },
      responseType: "arraybuffer"
    })
    .then((response) => {
      const reader = response.body.getReader(); // 获取读取器
      const decoder = new TextDecoder();
      // 声明处理函数
      const processRead = async (params) => {
        const { done, value } = params;
        if (!done) {
          // 如果已准备好则直接读取
          steamStr += decoder.decode(value);
          if (steamStr.includes("\n\n")) {
            const arr = steamStr.split("\n\n");
            try {
              while (arr.length > 1) {
                const current = arr.shift().replace("data:", "");
                if (current.startsWith("http")) {
                  // 音频文件
                  // await fetchAudio(current);
                  // 播放音频
                } else if (current.indexOf("phoneme") < 0) {
                  let res = await base64ToArrayBuffer(current);
                  sourceBuffer.appendBuffer(res);
                  if (isReady) {
                    // 如果已准备好则直接读取
                    isReady = false;
                  } else {
                    // 否则加入缓冲区
                    bufferList = [...bufferList, res];
                  }
                  if (
                    !play &&
                    audio.readyState === 4 &&
                    action_list.length > 0
                  ) {
                    // playAudio();
                    play = true;
                  }
                  // 二进制文件，暂时不用管
                } else {
                  // 文字信息文件
                  const new_res = JSON.parse(current);
                  new_res.map((item, index) => {
                    if (index <= currentIndex) {
                      return;
                    }
                    action_list.push(item);
                  });
                  currentIndex = new_res.length - 1;
                  playAnimate();
                }
                // onmessage(current);
                // return
              }
            } catch (err) {
              // console.log("err", err);
            }
            steamStr = arr[0];
          }
          // 读取完毕后递归进行下一次读取
          await reader.read().then(processRead);
        } else {
          // console.log("可读流读取完毕");
          isDone = true;
          playAudio();
          // console.log(mediaSource);
        }
      };

      // 开始读取
      reader.read().then((params) => {
        // console.log("params", params);
        processRead(params);
      });
    });
};
function playAudio() {
  audio.play();
}
audio.onplay = () => {
  console.log("开始播放");
  playBS();
};
// audio.onended = function () {
//   current_audio++;
//   // console.log("current_audio", current_audio);
//   // console.log(voice_list.length);
//   // playAudio();
// };
// audio.onerror = function (err) {
//   current_audio++;
//   // console.log(err);
//   // playAudio();
// };
audio.addEventListener("timeupdate", function () {
  // console.log(audio.currentTime);
  // if (audio.currentTime > 0 && current_audio === 0) {
  //   playBS();
  // }
});
function fetchAudio(url) {
  return new Promise((resolve, reject) => {
    fetchAB(url, (res) => {
      // console.log(res);
      if (isReady) {
        // 如果已准备好则直接读取
        sourceBuffer.appendBuffer(res);
        isReady = false;
      } else {
        // 否则加入缓冲区
        bufferList = [...bufferList, res];
      }
      resolve(res);
    });
  });
}
function fetchAB(url, cb) {
  console.log(url);
  var xhr = new XMLHttpRequest();
  xhr.open("get", url);
  xhr.responseType = "arraybuffer";
  xhr.onload = function () {
    cb(xhr.response);
  };
  xhr.send();
}
function stringToArrayBuffer(str) {
  const encoder = new TextEncoder(); // 创建TextEncoder实例
  const uint8Array = encoder.encode(str); // 将字符串转换为Uint8Array
  return uint8Array.buffer; // 返回Uint8Array的buffer属性，即ArrayBuffer
}
function base64ToArrayBuffer(base64String) {
  return new Promise((resolve, reject) => {
    // 使用atob()将Base64字符串转换为二进制字符串
    var binaryString = atob(base64String);
    var len = binaryString.length;
    // 创建一个Uint8Array，二进制字符串的长度
    var bytes = new Uint8Array(len);
    for (var i = 0; i < len; i++) {
      // 将字符串的每个字符转换为对应的ASCII码
      bytes[i] = binaryString.charCodeAt(i);
    }

    // 创建Blob对象
    var blob = new Blob([bytes], { type: "video/mp4" });
    // 使用FileReader读取Blob内容为ArrayBuffer
    var reader = new FileReader();
    reader.onload = function (e) {
      // 回调函数中的e.target.result就是ArrayBuffer对象
      var arrayBuffer = e.target.result;
      // 处理arrayBuffer
      console.log(arrayBuffer);
      resolve(arrayBuffer);
    };
    reader.readAsArrayBuffer(blob);
  });
}
